package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.repository;

import java.util.List;
import java.util.stream.Collectors;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.application.exceptions.ProcessObjectMetaSaveException;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.object.ProcessObjectMetaQueryVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.object.ProcessObjectMetaVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowObjectRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.entities.FlowDeployObjectMeta;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.entities.FlowDeployObjectMetaExample;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.entities.FlowDeployObjectMetaExample.Criteria;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.mapper.FlowDeployObjectMetaMapper;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author lich
 * @date 2021/11/15
 */
@Service
public class FlowObjectRepositoryImpl implements FlowObjectRepository {

    @Autowired
    private FlowDeployObjectMetaMapper flowDeployObjectMetaMapper;

    @Override
    public int saveProcessWithObjectMeta(ProcessObjectMetaVo processObjectMetaVo) {
        if (processObjectMetaVo.getDeployId() == null) {
            throw new ProcessObjectMetaSaveException("缺少deploy id");
        }
        if (processObjectMetaVo.getFlowCode() == null) {
            throw new ProcessObjectMetaSaveException("缺少flow code");
        }

        if (processObjectMetaVo.getObjectMetaCode() == null || processObjectMetaVo.getObjectMetaVersion() == null) {
            throw new ProcessObjectMetaSaveException("缺少对象类型的编码和版本信息");
        }
        if (processObjectMetaVo.getObjectMetaJson() == null) {
            throw new ProcessObjectMetaSaveException("缺少对象类型的完整信息(json内容）");
        }

        FlowDeployObjectMeta objectMeta = findExistingObjectMetaOnFlow(processObjectMetaVo);
        if (objectMeta == null) {
            objectMeta = new FlowDeployObjectMeta();
            BeanUtils.copyProperties(processObjectMetaVo, objectMeta);
            return flowDeployObjectMetaMapper.insertSelective(objectMeta);
        } else {
            objectMeta.setDeployId(processObjectMetaVo.getDeployId());
            objectMeta.setObjectMetaCode(processObjectMetaVo.getObjectMetaCode());
            objectMeta.setObjectMetaJson(processObjectMetaVo.getObjectMetaJson());
            objectMeta.setObjectMetaVersion(processObjectMetaVo.getObjectMetaVersion());
            objectMeta.setGmtModified(processObjectMetaVo.getGmtModified());
            return flowDeployObjectMetaMapper.updateByPrimaryKeyWithBLOBs(objectMeta);
        }

    }

    private FlowDeployObjectMeta findExistingObjectMetaOnFlow(ProcessObjectMetaVo processObjectMetaVo) {
        FlowDeployObjectMetaExample objectMetaExample = new FlowDeployObjectMetaExample();
        Criteria criteria = objectMetaExample.createCriteria();
        criteria.andFlowCodeEqualTo(processObjectMetaVo.getFlowCode());
        if (processObjectMetaVo.getNodeCode() == null) {
            criteria.andNodeCodeIsNull();
        } else {
            criteria.andNodeCodeEqualTo(processObjectMetaVo.getNodeCode());
        }
        objectMetaExample.setOrderByClause("gmt_create desc");
        List<FlowDeployObjectMeta> objectMetas = flowDeployObjectMetaMapper.selectByExample(objectMetaExample);
        if (CollectionUtils.isEmpty(objectMetas)) {
            return null;
        }
        return objectMetas.get(0);
    }

    @Override
    public PageInfo<ProcessObjectMetaVo> queryProcessObjectMeta(ProcessObjectMetaQueryVo queryVo) {
        PageHelper.startPage(queryVo.getPageNum(), queryVo.getPageSize());

        FlowDeployObjectMetaExample objectMetaExample = new FlowDeployObjectMetaExample();
        Criteria criteria = objectMetaExample.createCriteria();
        if (queryVo.getDeployId() != null) {
            criteria.andDeployIdEqualTo(queryVo.getDeployId());
        }
        if (queryVo.getFlowCode() != null) {
            criteria.andFlowCodeEqualTo(queryVo.getFlowCode());
        }
        if (queryVo.getNodeCode() != null) {
            criteria.andNodeCodeEqualTo(queryVo.getNodeCode());
        }
        if (queryVo.getObjectMetaCode() != null) {
            criteria.andObjectMetaCodeEqualTo(queryVo.getObjectMetaCode());
        }
        if (queryVo.getObjectMetaVersion() != null) {
            criteria.andObjectMetaVersionEqualTo(queryVo.getObjectMetaVersion());
        }

        objectMetaExample.setOrderByClause("gmt_create desc");

        List<FlowDeployObjectMeta> objectMetas;
        if (queryVo.getWithJson() != null && queryVo.getWithJson() == true) {
            objectMetas = flowDeployObjectMetaMapper.selectByExampleWithBLOBs(objectMetaExample);
        } else {
            objectMetas = flowDeployObjectMetaMapper.selectByExample(objectMetaExample);
        }

        List<ProcessObjectMetaVo> voList = objectMetas.stream()
            .map(FlowObjectRepositoryImpl::convert2Vo).collect(Collectors.toList());

        PageInfo<FlowDeployObjectMeta> pageInfo = new PageInfo<>(objectMetas);
        PageInfo<ProcessObjectMetaVo> newPageInfo = new PageInfo<>();
        BeanUtils.copyProperties(pageInfo, newPageInfo);

        newPageInfo.setList(voList);

        return newPageInfo;

    }

    private static ProcessObjectMetaVo convert2Vo(FlowDeployObjectMeta objectMeta) {
        ProcessObjectMetaVo metaVo = new ProcessObjectMetaVo();
        BeanUtils.copyProperties(objectMeta, metaVo);
        return metaVo;
    }
}
